#include "Dios.h"
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/wait.h>
#include <sys/time.h>
#include "../lib/Constantes.h"
#include "../lib/TiposDatos.h"

#define PROCESS_NAME "DIOS"

Dios::Dios(int cantidadPisos, int velocidadAsc, int capacidadAsc, int tiempo,
		int cantAsc, bool modoDebug, bool modoLog, bool modoSyn,
		bool modoCout) {

	this->modoDebug = modoDebug;
	this->modoLog = modoLog;
	this->modoSyn = modoSyn;
	this->modoCout = modoCout;
	// Logger
	Logger::getInstance()->setFlags(true, true, true, true);
	this->logger = Logger::getInstance();
	// Atributos
	this->cantidadPisos = cantidadPisos;
	this->cantidadAscensores = cantAsc;
	this->velocidadAsc = velocidadAsc;
	this->capacidadAsc = capacidadAsc;
	this->tiempo = tiempo;

	//Creamos los semaforos
	this->sync("Creamos Monitor Ascensores");
	this->mAscensores = new MonitorAscensores(this->cantidadAscensores,
			this->cantidadPisos, this->capacidadAsc, this->velocidadAsc);
	this->sync("Creamos Monitor Pisos");
	this->mPisos = new MonitorPisos(this->cantidadPisos);

	this->sem_asc = new ManejadorSemAscensores(this->cantidadAscensores);
	this->sem_pisos = new ManejadorSemPisos(this->cantidadPisos);
}

Dios::~Dios() {
	this->sync("Destruyendo Semaforos del Monitor Ascensor.");
	this->mAscensores->liberarSem();
	this->sync("Destruyendo Monitor Ascensor.");
	delete (this->mAscensores);
	this->sync("Monitor Ascensor destruido.");
	this->sync("Destruyendo Semaforos del Monitor Pisos.");
	this->mPisos->liberarSem();
	this->sync("Destruyendo Monitor Pisos.");
	delete (this->mPisos);
	this->sync("Monitor Pisos destruido.");

	this->sem_asc->liberarSemaforos();
	delete (this->sem_asc);
	this->sem_pisos->liberarSemaforos();
	delete (this->sem_pisos);
}

void Dios::log(string message) {
	string name = PROCESS_NAME;
	string msg = name + ": " + message;
	logger->loggearLog(msg);
}

void Dios::debug(string message) {
	string name = PROCESS_NAME;
	string msg = name + ": " + message;
	logger->loggearDebug(msg);
}

void Dios::sync(string message) {
	string name = PROCESS_NAME;
	string msg = name + ": " + message;
	logger->loggearSynchro(msg);
}

int Dios::start() {
        string message;
        // Parametros
        char tiempoGeneracionPersonas[32], cantidadAscensores[32], totalPisos[32],
                        velocidad[32], modoDebug[32], modoLog[32], modoSyn[32],
                        modoCout[32], capacidadAscensor[32];
        sprintf(totalPisos, "%d", this->cantidadPisos);
        sprintf(cantidadAscensores, "%d", this->cantidadAscensores);
        sprintf(capacidadAscensor, "%d", this->capacidadAsc);
        sprintf(velocidad, "%d", this->velocidadAsc);
        sprintf(tiempoGeneracionPersonas, "%d", this->tiempo);
        sprintf(modoDebug, "%d", this->modoDebug);
        sprintf(modoLog, "%d", this->modoLog);
        sprintf(modoSyn, "%d", this->modoSyn);
        sprintf(modoCout, "%d", this->modoCout);

        this->log("Inicializamos Monitor Ascensores");
        this->mAscensores->inicializar();
        this->log("Inicializamos Monitor Pisos");
        this->mPisos->inicializar();

        this->log("Inicializamos Manejador Ascensores");
        this->sem_asc->inicializar();
        this->log("Inicializamos Manejador Pisos");
        this->sem_pisos->inicializar();

        this->log("Inician las creaciones de Dios");
        this->log("El primer día creo la interfaz");
        pid_t pidInterfaz = fork();
        if (pidInterfaz == 0) {
                //Proceso Interfaz
                this->debug(
                                "Soy el proceso Inferfaz. Por ahora sin interfaz operativa.");
                exit(0);
        } else {
                this->log("El segundo día creo el ControladorCentral");
                pid_t pidControlador = fork();
                if (pidControlador == 0) {
                        //Proceso Controlador Central
                        this->debug("Iniciando el Controlador Central.");
                        execl("../ControladorCentral/Debug/ControladorCentral", "Dios",
                                        cantidadAscensores, totalPisos, capacidadAscensor, velocidad,
                                        modoDebug, modoLog, modoSyn, modoCout, NULL);
                        this->debug("Error al iniciar el Controlador Central.");
                        exit(0);
                } else {
                        this->log("El tercer día creó el GeneradorDeAscensores");
                        pid_t pidGenAscensores = fork();
                        if (pidGenAscensores == 0) {
                                //Proceso Generador De Ascensores
                                this->debug("Iniciando el Generador De Ascensores.");
                                execl("../GeneradorDeAscensores/Debug/GeneradorDeAscensores",
                                                "Dios", cantidadAscensores, totalPisos, velocidad,
                                                modoDebug, modoLog, modoSyn, modoCout,
                                                capacidadAscensor, NULL);
                                this->debug("Error al iniciar el Generador De Ascensores.");
                                exit(0);
                        } else {
                                this->log("El cuarto día creo el Generador de Personas");
                                pid_t pidGenPersonas = fork();
                                if (pidGenPersonas == 0) {
                                        //Proceso Generador de personas
                                        this->debug("Iniciando el Generador De Personas.");
                                        char controlador[32];
                                        sprintf(controlador, "%d", pidControlador);
                                        execl("../GeneradorDePersonas/Debug/GeneradorDePersonas",
                                                        "Dios", tiempoGeneracionPersonas, totalPisos,
                                                        cantidadAscensores, capacidadAscensor, velocidad,
                                                        controlador, modoDebug, modoLog, modoSyn,
                                                        modoCout, NULL);
                                        this->debug("Error al iniciar el Generador de Personas");
                                        exit(0);
                                } else {
                                        this->log(
                                                        "El quinto día esperó a que se termine la ejecución "
                                                                        "del Controlador Central.");
                                        int estado;
                                        waitpid(pidControlador, &estado, 0);
                                        this->log("El finde descanso");
                                        return 0;
                                }
                        }
                }
        }
}


